﻿Option Strict On
Imports System.ComponentModel

<ToolboxBitmap(GetType(System.Windows.Forms.TabControl))> _
Public Class TabControlEx
    Inherits TabControl


    Private Declare Auto Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    Protected CloseButtonCollection As New Dictionary(Of Button, TabPage)
    Private _ShowCloseButtonOnTabs As Boolean = True

    <Browsable(True), DefaultValue(True), Category("Behavior"), Description("Indicates whether a close button should be shown on each TabPage")> _
    Public Property ShowCloseButtonOnTabs() As Boolean
        Get
            Return _ShowCloseButtonOnTabs
            'Change this to show the close button
            'Return False
        End Get
        Set(ByVal value As Boolean)
            _ShowCloseButtonOnTabs = value
            For Each btn In CloseButtonCollection.Keys
                btn.Visible = _ShowCloseButtonOnTabs
                'and this
                btn.Visible = False
            Next
            RePositionCloseButtons()
        End Set
    End Property

    Protected Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()
        RePositionCloseButtons()
    End Sub

    Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
        If Not TabPages.Count = 1 Then
            MyBase.OnControlAdded(e)
            Dim tp As TabPage = DirectCast(e.Control, TabPage)
            Dim rect As Rectangle = Me.GetTabRect(Me.TabPages.IndexOf(tp))
            Dim btn As Button = AddCloseButton(tp)
            btn.Size = New Size(rect.Height - 1, rect.Height - 1)
            btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
            SetParent(btn.Handle, Me.Handle)
            AddHandler btn.Click, AddressOf OnCloseButtonClick
            CloseButtonCollection.Add(btn, tp)
        End If

    End Sub

    Protected Overrides Sub OnControlRemoved(ByVal e As System.Windows.Forms.ControlEventArgs)
        Dim btn As Button = CloseButtonOfTabPage(DirectCast(e.Control, TabPage))
        RemoveHandler btn.Click, AddressOf OnCloseButtonClick
        CloseButtonCollection.Remove(btn)
        SetParent(btn.Handle, Nothing)
        btn.Dispose()
        MyBase.OnControlRemoved(e)
    End Sub

    Protected Overrides Sub OnLayout(ByVal levent As System.Windows.Forms.LayoutEventArgs)
        MyBase.OnLayout(levent)
        RePositionCloseButtons()
    End Sub

    Public Event CloseButtonClick As CancelEventHandler
    Protected Overridable Sub OnCloseButtonClick(ByVal sender As Object, ByVal e As EventArgs)
        If Not DesignMode Then
            Dim btn As Button = DirectCast(sender, Button)
            Dim tp As TabPage = CloseButtonCollection(btn)
            Dim ee As New CancelEventArgs
            RaiseEvent CloseButtonClick(sender, ee)
            If Not ee.Cancel Then
                If SelectedTab Is tp Then
                    Me.SelectedTab = TabPages(TabPages.IndexOf(tp) - 1)
                End If

                Me.TabPages.Remove(tp)
                RePositionCloseButtons()
            End If
        End If
    End Sub

    Protected Overridable Function AddCloseButton(ByVal tp As TabPage) As Button
        Dim closeButton As New Button
        With closeButton
            '' TODO: Give a good visual appearance to the Close button, maybe by assigning images etc.
            ''       Here I have not used images to keep things simple.
            .Text = "X"
            .FlatStyle = FlatStyle.Flat
            .BackColor = Color.FromKnownColor(KnownColor.Black)
            .ForeColor = Color.White
            .Font = New Font("Microsoft Sans Serif", 6, FontStyle.Bold)
        End With
        Return closeButton
    End Function

    Public Sub RePositionCloseButtons()
        For Each item In CloseButtonCollection
            RePositionCloseButtons(item.Value)
        Next
    End Sub

    Public Sub RePositionCloseButtons(ByVal tp As TabPage)
        Dim btn As Button = CloseButtonOfTabPage(tp)
        If btn IsNot Nothing Then
            Dim tpIndex As Integer = Me.TabPages.IndexOf(tp)
            If tpIndex >= 0 Then
                Dim rect As Rectangle = Me.GetTabRect(tpIndex)
                If Me.SelectedTab Is tp Then
                    btn.BackColor = Color.PaleVioletRed
                    btn.Size = New Size(rect.Height - 1, rect.Height - 1)
                    btn.Location = New Point(rect.X + rect.Width - rect.Height, rect.Y + 1)
                Else
                    btn.BackColor = Color.FromKnownColor(KnownColor.PaleVioletRed)
                    btn.Size = New Size(rect.Height - 1, rect.Height - 1)
                    btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
                End If
                btn.Visible = ShowCloseButtonOnTabs
                btn.BringToFront()
            End If
        End If
    End Sub

    Protected Function CloseButtonOfTabPage(ByVal tp As TabPage) As Button
        Return (From item In CloseButtonCollection Where item.Value Is tp Select item.Key).FirstOrDefault
    End Function

#Region "Tab Management"
    Public Function CanAddNewTab(ByVal p_ObjectName As String) As Boolean
        Return (From u In Me.TabPages Where CType(u, TabPage).ToolTipText = p_ObjectName Or CType(u, TabPage).Text.Trim = p_ObjectName.Trim Or CStr(CType(u, TabPage).Tag) = p_ObjectName.Trim Select u).FirstOrDefault Is Nothing
    End Function

    Public Sub AddNewTab(ByVal p_strTabTitle As String, ByVal bFill As Boolean, ByVal ParamArray Controls() As Control)
        p_strTabTitle += "     "
        If Not Me.TabCount = 0 Then
            If CanAddNewTab(p_strTabTitle) Then
                Me.TabPages.Insert(Me.SelectedIndex + 1, p_strTabTitle)
                SetTabNameCorrectly(Me.SelectedIndex + 1)
                Me.SelectedIndex = Me.SelectedIndex + 1
                Me.SelectedTab.Tag = p_strTabTitle
            Else
                SelectTabByName(p_strTabTitle)
                ' Browser.RemoveSelectedTab()
                Me.TabPages.Insert(Me.SelectedIndex + 1, p_strTabTitle)
                SetTabNameCorrectly(Me.SelectedIndex + 1)
                Me.SelectedIndex = Me.SelectedIndex + 1
                Me.SelectedTab.Tag = p_strTabTitle
            End If
        Else
            Me.TabPages.Add(p_strTabTitle)
        End If
        Dim TableLayout As New TableLayoutPanel()


        Dim LayoutRow As Integer = 0
        For Each Con In Controls

            If Not Con Is Nothing Then
                'p_oControl.Anchor = AnchorStyles.Bottom And AnchorStyles.Left And AnchorStyles.Right And AnchorStyles.Top
                If bFill Then
                    Con.Dock = DockStyle.Fill
                    'Con.Anchor = AnchorStyles.Left And AnchorStyles.Right And AnchorStyles.Top And AnchorStyles.Bottom
                Else
                    Con.Anchor = AnchorStyles.Top
                    'TableLayout.AutoSize = True
                End If

                'TableLayout.AutoScroll = True
                TableLayout.CellBorderStyle = TableLayoutPanelCellBorderStyle.Outset
                TableLayout.Controls.Add(Con, 0, LayoutRow)
                TableLayout.AutoScroll = True
                Con.BringToFront()




                LayoutRow += 1

            End If
        Next
        If Me.TabPages.Count = 0 Then
            TableLayout.ContextMenuStrip = New ContextMenuStrip
        End If
        TableLayout.Dock = DockStyle.Fill
        Me.TabPages(Me.SelectedIndex).Controls.Add(TableLayout)
        If Not bFill Then
            'Me.TabPages(Me.SelectedIndex).BackColor = Color.DimGray

            TableLayout.BackColor = Color.LightSlateGray

            'Me.TabPages(Me.SelectedIndex).Anchor = AnchorStyles.None
        End If

    End Sub

    Public Sub SelectTabByName(ByVal p_strTabName As String)
        Me.SelectedTab = ((From u In Me.TabPages Where CType(u, TabPage).Text.Trim = p_strTabName.Trim Or CType(u, TabPage).ToolTipText = p_strTabName Or CStr(CType(u, TabPage).Tag) = p_strTabName Select CType(u, TabPage)).FirstOrDefault)
    End Sub

    Public Sub RemoveSelectedTab()
        Try
            Dim Index As Integer
            Index = Me.SelectedIndex

            Me.TabPages.Remove(Me.SelectedTab)
            Me.SelectTab(Index - 1)

        Catch ex As Exception
            Outils.ErrorProviderFunctions.AddError(Me, Nothing, "Le contrôle que vous essayez de fermer n'existe pas.")
        End Try

    End Sub

    Public Sub RemoveSelectedTabByName(ByVal p_name As String)
        'Auteur: Marc-Antoine Beaulieu
        Try
            Me.TabPages.Remove(Me.TabPages(p_name))
        Catch ex As Exception
            'Browser.AddError(Nothing, "Le contrôle que vous essayez de fermer n'existe pas.", True, Browser.ErrorType.Critical)
        End Try

    End Sub
    Public Sub RenameSelectedTab(ByVal p_strNewTabText As String)
        Try
            Me.SelectedTab.Text = p_strNewTabText
            SetTabNameCorrectly(Me.SelectedIndex)
            RePositionCloseButtons()
        Catch ex As Exception
            '  Browser.AddError(Nothing, "Le contrôle que vous essayez de renommer n'existe pas.", True, Browser.ErrorType.Critical)
        End Try
    End Sub


    Private Sub SetTabNameCorrectly(Optional ByVal p_TabPageIndex As Integer = -1)
        For Each TabToCheck In (From u In TabPages.OfType(Of TabPage)() Where TabPages.IndexOf(u) = p_TabPageIndex Or p_TabPageIndex = -1 Select u).ToList
            If TabToCheck.Text.Trim.Length > 35 Then
                TabToCheck.ToolTipText = TabToCheck.Text.Trim
                TabToCheck.Text = TabToCheck.Text.Trim.Substring(0, 35) + "[...]"
                RePositionCloseButtons()
            End If
        Next
    End Sub
#End Region


End Class
